package com.myk.game.gobangchess.rooms.oldrooms;

import com.myk.game.gobangchess.Room;
import com.myk.game.gobangchess.constants.BoardStyleData;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.signs.AroundSign;
import com.myk.game.gobangchess.utils.GridsUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 绳棋房间
 */
public class CordRoom extends Room {

    private int state = 0;//0落子，1拉绳
    private int[] firstPoint = null;
    private int[] secondPoint = null;

    private boolean canMoveTwice;

    private List<Integer> cords = new ArrayList<>();//存储绳子的提示
    private List<Integer> canMoves = new ArrayList<>();


    public CordRoom(String roomName) {
        super(roomName, "\t\t绳棋，夏日改编的新棋。", "绳棋", BoardStyleData.getGoBangStyle(8, 8), true, true);
    }

    @Override
    public String getRuleText() {
        return "【定义】\n" +
                "绳：宽度为1的棋串\n" +
                "\n" +
                "轮到你时，可在空格落一子；\n" +
                "\n" +
                "拉绳：落子后，选一枚同线的己方棋子，在两子之间所有格子落下己方棋子（仅当落子和选子之间只有敌方垂直的「绳」或空格时。）\n" +
                "\n" +
                "打结禁手：任何行动都不允许己方棋子形成「田形」\n" +
                "边角限制：落子在边角时，必须伴随着通过拉绳割断对方的绳子\n" +
                "\n" +
                "无法行动时，再次轮到对方行动\n" +
                "双方无法行动时，最大连通块更大的一方赢\n";
    }

    @Override
    protected void doStart() {
        getTheCanMoveSign(1);
        super.doStart();
    }

    @Override
    public void doRule(int row, int col, int value) {
        if (step < 2) {
            if (curGrids[row][col] == 0) {
                if (row != 0 && col != 0 && row != curGrids.length - 1 && col != curGrids[0].length - 1) {
                    curGrids[row][col] = value;
                    firstPoint = new int[]{row, col, value};
                    noticeChangeMove();
                }
            }
        } else {
            if (state == 0) {
                if (curGrids[row][col] == 0) {
                    //System.out.println("第2个if");
                    //System.out.println(row + " " + col);
                    //System.out.println((curGrids.length - 1) + " " + (curGrids[0].length - 1));
                    if (checkSquare(curGrids, row, col, cur)) {
                        //System.out.println("第2个if");
                        if (row != 0 && col != 0 &&
                                row != curGrids.length - 1 &&
                                col != curGrids[0].length - 1) {//不能落在外圈
                            //System.out.println("第3个if1");
                            curGrids[row][col] = value; //
                            firstPoint = new int[]{row, col, value};
                            noticeStillMove();
                        } else if (isLineCut(row, col, cur)) {//判断特殊情况：落在外圈但可以拉线并切断
                            //System.out.println("第3个if2");
                            state = 2;
                            curGrids[row][col] = value; //
                            firstPoint = new int[]{row, col, value};
                            noticeStillMove();
                        }
                    }
                }
            } else if (state == 1) {
                if (curGrids[row][col] == value) {
                    if (!(row == firstPoint[0] && col == firstPoint[1])) {
                        if (row == firstPoint[0]) {
                            if (checkLineSquare(row, col, firstPoint[0], firstPoint[1], cur)) {
                                secondPoint = new int[]{row, col, value};
                                makeLine(0);
                                checkNoticeMove();
                            }
                        } else if (col == firstPoint[1]) {
                            if (checkLineSquare(row, col, firstPoint[0], firstPoint[1], cur)) {
                                secondPoint = new int[]{row, col, value};
                                makeLine(1);
                                checkNoticeMove();
                            }
                        }
                    } else
                        checkNoticeMove();
                }
            } else if (state == 2) {//边界切断状态  未完成
                if (curGrids[row][col] == value) {
                    if (!(row == firstPoint[0] && col == firstPoint[1])) {
                        if (row == firstPoint[0]) {
                            if (checkLineSquare(row, col, firstPoint[0], firstPoint[1], cur)) {
                                if (checkCut(row, col, firstPoint[0], firstPoint[1], cur)) {
                                    secondPoint = new int[]{row, col, value};
                                    makeLine(0);
                                    checkNoticeMove();
                                }
                            }
                        } else if (col == firstPoint[1]) {
                            if (checkLineSquare(row, col, firstPoint[0], firstPoint[1], cur)) {
                                if (checkCut(row, col, firstPoint[0], firstPoint[1], cur)) {
                                    secondPoint = new int[]{row, col, value};
                                    makeLine(1);
                                    checkNoticeMove();
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private void printMatrix(int[][] matrix) {
        for (int[] row : matrix) {
            for (int num : row) {
                System.out.print(num + " ");
            }
            //System.out.println();
        }
    }

    private void checkNoticeMove() {//检查下家是否有棋可走，若都不能走则结算
        int opCur = cur == 1 ? 2 : 1;
        if (checkCanMove(opCur)) {
            noticeChangeMove();
        } else if (checkCanMove(cur)) {
            noticeMoveAgain();
        } else {
            checkWin();
        }
    }

    private void showScore(){
        whiteScore = getMaxConnectedOnes(2);
        blackScore = getMaxConnectedOnes(1);
    }
    private void checkWin() {//结算
        whiteScore = getMaxConnectedOnes(2);
        blackScore = getMaxConnectedOnes(1);
        if (blackScore > whiteScore) {
            doOver(WinMode.BLACK_WIN, player_black.getNickNameOrTemp() + "战胜" + player_white.getNickNameOrTemp());
        } else if (blackScore < whiteScore) {
            doOver(WinMode.WHITE_WIN, player_white.getNickNameOrTemp() + "战胜" + player_black.getNickNameOrTemp());
        } else {
            doOver(WinMode.BOTH_DRAW, player_black.getNickNameOrTemp() + "-黑棋战平" + player_white.getNickNameOrTemp() + "-白棋");
        }
    }

    private int getMaxConnectedOnes(int theCur) {
        int maxCount = 0;
        // 遍历棋盘中的每个格子
        for (int i = 0; i < curGrids.length; i++) {
            for (int j = 0; j < curGrids[0].length; j++) {
                if (curGrids[i][j] == theCur) {
                    int count = dfs(GridsUtils.copyGrids(curGrids), i, j, theCur);
                    maxCount = Math.max(maxCount, count);
                }
            }
        }

        return maxCount;
    }

    private int dfs(int[][] curGrids, int row, int col, int theCur) {
        // 边界条件判断
        if (row < 0 || row >= curGrids.length || col < 0 || col >= curGrids[0].length || curGrids[row][col] != theCur) {
            return 0;
        }

        // 将当前格子标记为已访问
        curGrids[row][col] = -1;

        int count = 1; // 当前格子包含的theCur的个数

        // 递归搜索上下左右四个方向的格子
        count += dfs(curGrids, row - 1, col, theCur); // 上方格子
        count += dfs(curGrids, row + 1, col, theCur); // 下方格子
        count += dfs(curGrids, row, col - 1, theCur); // 左方格子
        count += dfs(curGrids, row, col + 1, theCur); // 右方格子

        return count;
    }

    private void noticeMoveAgain() {
        addHistory(); //添加历史记录
//        System.out.println("对家无法行动，自己再次行动");
        state = 0;
        getTheCanMoveSign(cur);
        stepAdd();;
        if (cur == 1) {
            noticeBlackMove();
        } else if (cur == 2) {
            noticeWhiteMove();
        }
        firstPoint = null;
        secondPoint = null;
        cords = new ArrayList<>();
    }

    private boolean isLineCut(int row, int col, int theCur) {
        for (int i = 0; i < curGrids.length; i++) {
            for (int j = 0; j < curGrids[i].length; j++) {
                if (curGrids[i][j] == theCur) {
                    if (!(i == row && j == col)) {
                        if (i == row || j == col) {
                            if (checkLineSquare(i, j, row, col, theCur)) {
                                if (checkCut(i, j, row, col, theCur))
                                    return true;
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

    private boolean checkCut(int i, int j, int row, int col, int theCur) {//检查是否能切断
        int[][] newCurGrids = GridsUtils.copyGrids(curGrids);
        int opCur = theCur == 1 ? 2 : 1;
        if (i == row) {
            int col1 = Math.min(j, col);
            int col2 = Math.max(j, col);
            for (int newCol = col1 + 1; newCol < col2; newCol++) {
                if (newCurGrids[i][newCol] == opCur)
                    return true;
            }
        } else if (j == col) {
            int row1 = Math.min(i, row);
            int row2 = Math.max(i, row);
            for (int newRow = row1 + 1; newRow < row2; newRow++) {
                if (newCurGrids[newRow][j] == opCur)
                    return true;
            }
        }
        return false;
    }

    private boolean checkLineSquare(int row, int col, int preRow, int preCol, int theCur) {
        int[][] newCurGrids = GridsUtils.copyGrids(curGrids);
        newCurGrids[preRow][preCol] = theCur;
        int opCur = theCur == 1 ? 2 : 1;
        int opLineLength = 0;
        if (row == preRow) {
            int col1 = Math.min(preCol, col);
            int col2 = Math.max(preCol, col);
            for (int newCol = col1 + 1; newCol < col2; newCol++) {
                if (newCurGrids[preRow][newCol] == theCur ||
                        !checkSquare(newCurGrids, row, newCol, theCur))
                    return false;
                if (newCurGrids[preRow][newCol] == opCur) {
                    opLineLength++;
                    if (opLineLength == 2)
                        return false;
                } else
                    opLineLength = 0;
                newCurGrids[preRow][newCol] = theCur;
            }
        } else if (col == preCol) {
            int row1 = Math.min(preRow, row);
            int row2 = Math.max(preRow, row);
            for (int newRow = row1 + 1; newRow < row2; newRow++) {
                if (newCurGrids[newRow][preCol] == theCur ||
                        !checkSquare(newCurGrids, newRow, col, theCur))
                    return false;
                if (newCurGrids[newRow][preCol] == opCur) {
                    opLineLength++;
                    if (opLineLength == 2)
                        return false;
                } else
                    opLineLength = 0;
                newCurGrids[newRow][preCol] = theCur;
            }
        }
        return true;
    }

    private void makeLine(int r) {
        cords = new ArrayList<>();
        if (r == 0) {
            int col1 = Math.min(firstPoint[1], secondPoint[1]);
            int col2 = Math.max(firstPoint[1], secondPoint[1]);
            for (int col = col1 + 1; col < col2; col++) {
                curGrids[firstPoint[0]][col] = cur;
                cords.add(getIndex(firstPoint[0], col));
            }
        } else if (r == 1) {
            int row1 = Math.min(firstPoint[0], secondPoint[0]);
            int row2 = Math.max(firstPoint[0], secondPoint[0]);
            for (int row = row1 + 1; row < row2; row++) {
                curGrids[row][firstPoint[1]] = cur;
                cords.add(getIndex(row, firstPoint[1]));
            }
        }
    }

    @Override
    public void resetGrids() {
        super.resetGrids();
        firstPoint = null;
        secondPoint = null;
        cords = new ArrayList<>();
        state = 0;
        blackScore = 0;
        whiteScore = 0;
    }

    protected void noticeChangeMove() {
        showScore();
        addHistory(); //添加历史记录
//        System.out.println("对家行动");
        int opCur = cur == 1 ? 2 : 1;
        state = 0;
        getTheCanMoveSign(opCur);
        stepAdd();;
        if (cur == 1) {
            noticeWhiteMove();
        } else if (cur == 2) {
            noticeBlackMove();
        }
        firstPoint = null;
        secondPoint = null;
        cords = new ArrayList<>();
    }

    private boolean checkCanMove(int theCur) {
        for (int i = 0; i < curGrids.length; i++) {
            for (int j = 0; j < curGrids[0].length; j++) {
                if (curGrids[i][j] == 0) {
                    if (checkSquare(curGrids, i, j, theCur)) {
                        if (i != 0 && j != 0 &&
                                i != curGrids.length - 1 &&
                                j != curGrids[0].length - 1) {
                            return true;
                        } else {
                            if (isLineCut(i, j, theCur))
                                return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    private void noticeStillMove() {
        addHistory(); //添加历史记录
        if (state != 2)
            state = 1;
        getTheCanMoveSign(cur);
        if (!canMoveTwice)
            checkNoticeMove();
        else {
            showScore();
            if (cur == 2) {
                noticeAllRefreshGameInfo();
            } else if (cur == 1) {
                noticeAllRefreshGameInfo();
            }
        }

    }

    @Override
    public String getGameInfo() {
        signList.clear();
        if (firstPoint != null && secondPoint != null) {
            signList.add(new AroundSign(getIndex(firstPoint[0], firstPoint[1]), "#00000000", "#FF00FF00", 1.2f));
            signList.add(new AroundSign(getIndex(secondPoint[0], secondPoint[1]), "#00000000", "#FF0000FF", 1.2f));
            if (!cords.isEmpty())
                signList.add(new AroundSign(cords, "#00000000", "#FF800080", 1.2f));
        } else if (firstPoint != null) {
            signList.add(new AroundSign(getIndex(firstPoint[0], firstPoint[1]), "#00000000", "#FF00FF00", 1.2f));
            if (!cords.isEmpty())
                signList.add(new AroundSign(cords, "#00000000", "#FF800080", 1.2f));
        }

        if (!canMoves.isEmpty())
            signList.add(new AroundSign(canMoves, "#4400EE00", "#00000000", 1.2f));
        return super.getGameInfo();
    }

    private void getTheCanMoveSign(int theCur) {
        canMoves = new ArrayList<>();
        if (state == 0) {
            for (int i = 0; i < curGrids.length; i++) {
                for (int j = 0; j < curGrids[0].length; j++) {
                    if (curGrids[i][j] == 0) {
                        if (checkSquare(curGrids, i, j, theCur)) {
                            if (i != 0 && j != 0 &&
                                    i != curGrids.length - 1 &&
                                    j != curGrids[0].length - 1) {
                                canMoves.add(getIndex(i, j));
//                            return true;
                            } else {
                                if (isLineCut(i, j, theCur))
                                    canMoves.add(getIndex(i, j));//                                return true;
                            }
                        }
                    }
                }
            }
        } else if (state == 1) {
            canMoves.add(getIndex(firstPoint[0], firstPoint[1]));
            canMoveTwice = false;
            for (int i = 0; i < curGrids.length; i++) {
                for (int j = 0; j < curGrids[0].length; j++) {
                    if (curGrids[i][j] == theCur) {
                        if (!(i == firstPoint[0] && j == firstPoint[1])) {
                            if (i == firstPoint[0]) {
                                if (checkLineSquare(i, j, firstPoint[0], firstPoint[1], theCur)) {
                                    canMoves.add(getIndex(i, j));
                                    canMoveTwice = true;
                                }
                            } else if (j == firstPoint[1]) {
                                if (checkLineSquare(i, j, firstPoint[0], firstPoint[1], theCur)) {
                                    canMoves.add(getIndex(i, j));
                                    canMoveTwice = true;
                                }
                            }
                        }
                    }
                }
            }
        } else if (state == 2) {
            canMoveTwice = false;
            for (int i = 0; i < curGrids.length; i++) {
                for (int j = 0; j < curGrids[0].length; j++) {
                    if (curGrids[i][j] == theCur) {
                        if (!(i == firstPoint[0] && j == firstPoint[1])) {
                            if (i == firstPoint[0]) {
                                if (checkLineSquare(i, j, firstPoint[0], firstPoint[1], cur)) {
                                    if (checkCut(i, j, firstPoint[0], firstPoint[1], cur)) {
                                        canMoves.add(getIndex(i, j));
                                        canMoveTwice = true;
                                    }
                                }
                            } else if (j == firstPoint[1]) {
                                if (checkLineSquare(i, j, firstPoint[0], firstPoint[1], cur)) {
                                    if (checkCut(i, j, firstPoint[0], firstPoint[1], cur)) {
                                        canMoves.add(getIndex(i, j));
                                        canMoveTwice = true;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private boolean checkSquare(int[][] grids, int row, int col, int theCur) {
//        int[][] rightTop = {{1, -1}, {1, 0}, {0, -1}};
//        int[][] leftBottom = {{-1, 1}, {-1, 0}, {0, 1}};
        int[][] leftTop = {{-1, -1}, {-1, 0}, {0, -1}};
        int[][] rightTop = {{-1, 1}, {-1, 0}, {0, 1}};
        int[][] leftBottom = {{1, -1}, {1, 0}, {0, -1}};
        int[][] rightBottom = {{1, 1}, {1, 0}, {0, 1}};
        boolean[] isValid = new boolean[4];

        if (row == 0) {
            isValid[0] = true;
            isValid[1] = true;
        }
        if (row == grids.length - 1) {
            isValid[2] = true;
            isValid[3] = true;
        }
        if (col == 0) {
            isValid[0] = true;
            isValid[2] = true;
        }
        if (col == grids[0].length - 1) {
            isValid[1] = true;
            isValid[3] = true;
        }

        for (int[] offset : leftTop) {
            int newRow = row + offset[0];
            int newCol = col + offset[1];
            if (newRow >= 0 && newRow < grids.length && newCol >= 0 && newCol < grids[newRow].length) {
                if (grids[newRow][newCol] != theCur)
                    isValid[0] = true;
            }
        }
        for (int[] offset : rightTop) {
            int newRow = row + offset[0];
            int newCol = col + offset[1];
            if (newRow >= 0 && newRow < grids.length && newCol >= 0 && newCol < grids[newRow].length) {
                if (grids[newRow][newCol] != theCur)
                    isValid[1] = true;
            }
        }
        for (int[] offset : leftBottom) {
            int newRow = row + offset[0];
            int newCol = col + offset[1];
            if (newRow >= 0 && newRow < grids.length && newCol >= 0 && newCol < grids[newRow].length) {
                if (grids[newRow][newCol] != theCur)

                    isValid[2] = true;
            }
        }
        for (int[] offset : rightBottom) {
            int newRow = row + offset[0];
            int newCol = col + offset[1];
            if (newRow >= 0 && newRow < grids.length && newCol >= 0 && newCol < grids[newRow].length) {
//                System.out.println(newRow + " " + newCol + " " + grids[newRow][newCol]);
                if (grids[newRow][newCol] != theCur)
                    isValid[3] = true;
            }
        }
        for (boolean valid : isValid) {
            if (!valid) {
                return false; // 如果有任一方向不满足条件，则返回 false
            }
        }

        return true; // 如果所有方向都满足条件，则返回 true
    }

    @Override
    public void doOver(int winMode, String winMsg) {
        state = 0;
        firstPoint = null;
        secondPoint = null;
        cords = new ArrayList<>();
        canMoves = new ArrayList<>();
        canMoveTwice = false;
        super.doOver(winMode, winMsg);
    }

//    @Override
//    public void noticeBlackMove() {
//        if (player_black != null) {
//            player_black.registerCustomBottom(new CustomBottom(this, "复盘", (player) -> {
//                curGrids = new int[][]{
//                        {0, 1, 0, 0, 0, 0, 0, 0},
//                        {2, 1, 2, 2, 2, 0, 2, 0},
//                        {0, 1, 1, 1, 2, 2, 2, 0},
//                        {0, 2, 2, 1, 1, 0, 2, 0},
//                        {0, 0, 2, 2, 1, 2, 2, 2},
//                        {0, 2, 2, 1, 1, 1, 1, 1},
//                        {0, 0, 2, 1, 2, 1, 2, 1},
//                        {1, 1, 1, 1, 1, 1, 1, 1}
//                };
//                showScore();
//                addHistory(); //添加历史记录
////        System.out.println("对家行动");
//                int opCur = cur == 1 ? 2 : 1;
//                state = 0;
//                getTheCanMoveSign(opCur);
//                stepAdd();;
//                    noticeBlackMove();
//                firstPoint = null;
//                secondPoint = null;
//                cords = new ArrayList<>();
//            }));
//        }
//        super.noticeBlackMove();
//    }
}
